package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.PmMaterialItem;
import com.ruoyi.system.domain.PmMaterialList;
import com.ruoyi.system.dto.ProjectDTO;
import com.ruoyi.system.mapper.PmMaterialItemMapper;
import com.ruoyi.system.mapper.PmMaterialListMapper;
import com.ruoyi.system.service.IOperationLogService;
import com.ruoyi.system.service.IPmMaterialListService;
import com.ruoyi.system.service.ProjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class PmMaterialListServiceImpl extends ServiceImpl<PmMaterialListMapper, PmMaterialList> implements IPmMaterialListService {


    @Autowired
    private ObjectMapper objectMapper; // 用于JSON序列化（需Spring自动注入）

    @Autowired
    private PmMaterialListMapper materialListMapper;

    @Autowired
    private PmMaterialItemMapper materialItemMapper;

    @Autowired
    private IOperationLogService operationLogService;

    @Autowired
    private ProjectService projectService; // 项目表查询服务（关联t_project）

    @Override
    public IPage<PmMaterialList> selectMaterialListPage(int pageNum, int pageSize, PmMaterialList list) {
        Page<PmMaterialList> page = new Page<>(pageNum, pageSize);
        Long currentUserId = SecurityUtils.getUserId();
        boolean isAdmin = SecurityUtils.hasRole("admin");
        // 设计师仅能查看自己项目的合同：project_id in (select id from t_project where designer_id = currentUserId)
        if (!isAdmin && currentUserId != null) {
            list.setCreateUserId(currentUserId);
        }
        return materialListMapper.selectMaterialListPage(page, list);
    }

    @Transactional
    @Override
    public boolean updateMaterialList(PmMaterialList list, Long operatorId, String operatorName) {
        // 1. 校验清单是否存在
        Long listId = list.getId();
        if (listId == null) {
            throw new ServiceException("清单ID不能为空");
        }
        PmMaterialList oldList = getById(listId);
        if (oldList == null || oldList.getDeleted() == 1) {
            throw new ServiceException("物料清单不存在或已被删除（ID：" + listId + "）");
        }

        // 2. 对比修改前后的字段差异（仅记录被修改的字段）
        Map<String, Object> beforeData = new HashMap<>();
        Map<String, Object> afterData = new HashMap<>();

        // 可修改字段1：清单名称
        if (StringUtils.isNotBlank(list.getListName()) && !list.getListName().equals(oldList.getListName())) {
            beforeData.put("list_name", oldList.getListName());
            afterData.put("list_name", list.getListName());
        }

        // 可修改字段2：业主预算
        if (list.getOwnerBudget() != null && !list.getOwnerBudget().equals(oldList.getOwnerBudget())) {
            beforeData.put("owner_budget", oldList.getOwnerBudget());
            afterData.put("owner_budget", list.getOwnerBudget());
        }

        // 可修改字段3：备注
        if ((list.getRemark() == null && oldList.getRemark() != null)
                || (list.getRemark() != null && !list.getRemark().equals(oldList.getRemark()))) {
            beforeData.put("remark", oldList.getRemark());
            afterData.put("remark", list.getRemark());
        }

        // 3. 若无可修改字段，直接返回成功（避免无效更新）
        if (beforeData.isEmpty() && afterData.isEmpty()) {
            return true;
        }

        // 4. 填充不可修改字段（防止恶意篡改）
        list.setProjectId(oldList.getProjectId()); // 项目ID不可修改
        list.setProjectNo(oldList.getProjectNo()); // 项目编号不可修改
        list.setProjectName(oldList.getProjectName()); // 项目名称不可修改
        list.setCreateUserId(oldList.getCreateUserId()); // 创建人不可修改
        list.setCreateUserName(oldList.getCreateUserName()); // 创建人姓名不可修改
        list.setCreateTime(oldList.getCreateTime()); // 创建时间不可修改
        list.setUpdateTime(LocalDateTime.now()); // 更新时间自动刷新

        // 5. 执行更新操作
        boolean updateResult = updateById(list);
        if (updateResult) {
            // 6. 同步记录操作日志
            try {
                // 转换差异数据为JSON（仅包含被修改的字段）
                String beforeJson = objectMapper.writeValueAsString(beforeData);
                String afterJson = objectMapper.writeValueAsString(afterData);

                // 构建操作描述（简要说明修改内容）
                StringBuilder desc = new StringBuilder("修改物料清单：");
                if (beforeData.containsKey("list_name")) {
                    desc.append("名称从「").append(oldList.getListName()).append("」改为「").append(list.getListName()).append("」；");
                }
                if (beforeData.containsKey("owner_budget")) {
                    desc.append("业主预算从「").append(oldList.getOwnerBudget()).append("」改为「").append(list.getOwnerBudget()).append("」；");
                }
                if (beforeData.containsKey("remark")) {
                    desc.append("备注内容变更；");
                }

                // 调用日志服务保存
                operationLogService.saveMaterialLog(
                        listId,
                        oldList.getListName(), // 用原名称记录（若名称被修改）
                        operatorId,
                        operatorName,
                        "LIST_UPDATE", // 操作类型：清单修改
                        beforeJson,
                        afterJson,
                        desc.toString()
                );
            } catch (JsonProcessingException e) {
                // 日志JSON序列化失败不影响主业务，但需记录异常
                log.error("物料清单修改日志序列化失败：", e);
            }
        }
        return updateResult;
    }


    @Transactional
    @Override
    public boolean createMaterialList(PmMaterialList list) {
        // 1. 校验项目存在（关联t_project）
        ProjectDTO project = projectService.getProjectById(list.getProjectId());
        if (project == null) {
            throw new ServiceException("关联项目不存在（项目ID：" + list.getProjectId() + "）");
        }

        // 2. 自动填充项目编号/名称（冗余t_project字段）
        list.setProjectNo(project.getProjectNo());
        list.setProjectName(project.getProjectName());
        // 3. 默认清单名称
        if (list.getListName() == null || list.getListName().trim().isEmpty()) {
            list.setListName(project.getProjectName() + "-物料清单");
        }

        // 4. 初始化状态和时间
        list.setListStatus(1); // 已创建
        list.setCreateTime(LocalDateTime.now());
        list.setUpdateTime(LocalDateTime.now());
        list.setCreateUserId(getCurrentUserId()); // 若依工具类：获取当前登录用户ID
        list.setCreateUserName(getCurrentUserName()); // 获取当前登录用户名

        // 5. 保存清单
        boolean saveResult = save(list);
        if (saveResult) {
            // 6. 记录日志（复用t_operation_log）
            operationLogService.saveMaterialLog(
                    list.getId(),
                    list.getListName(),
                    list.getCreateUserId(),
                    list.getCreateUserName(),
                    "LIST_CREATE",
                    null,
                    "{\"list_status\":1,\"status_desc\":\"已创建\"}",
                    "创建物料清单（关联项目：" + project.getProjectName() + "）"
            );
        }
        return saveResult;
    }

    @Transactional
    @Override
    public boolean pushToOwner(Long listId, Long operatorId, String operatorName) {
        PmMaterialList list = getById(listId);
        if (list == null || list.getListStatus() != 1) {
            throw new ServiceException("仅“已创建”状态的清单可推送");
        }

        // 更新状态为“已推送”
        list.setListStatus(2);
        list.setUpdateTime(LocalDateTime.now());
        boolean updateResult = updateById(list);
        if (updateResult) {
            operationLogService.saveMaterialLog(
                    listId,
                    list.getListName(),
                    operatorId,
                    operatorName,
                    "LIST_PUSH",
                    "{\"list_status\":1,\"status_desc\":\"已创建\"}",
                    "{\"list_status\":2,\"status_desc\":\"已推送\"}",
                    "推送清单给业主"
            );
        }
        return updateResult;
    }

    @Transactional
    @Override
    public boolean cancelPush(Long listId, Long operatorId, String operatorName) {
        PmMaterialList list = getById(listId);
        if (list == null || list.getListStatus() != 2) {
            throw new ServiceException("仅“已推送”状态的清单可撤回");
        }

        // 更新状态为“已创建”
        list.setListStatus(1);
        list.setUpdateTime(LocalDateTime.now());
        boolean updateResult = updateById(list);
        if (updateResult) {
            operationLogService.saveMaterialLog(
                    listId,
                    list.getListName(),
                    operatorId,
                    operatorName,
                    "LIST_PUSH_CANCEL",
                    "{\"list_status\":2,\"status_desc\":\"已推送\"}",
                    "{\"list_status\":1,\"status_desc\":\"已创建\"}",
                    "撤回业主推送"
            );
        }
        return updateResult;
    }

    @Override
    public void calculateListSummary(Long listId) {
        // 查询清单下所有物料
        List<PmMaterialItem> items = materialItemMapper.selectList(
                new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<PmMaterialItem>()
                        .eq("list_id", listId)
        );

        // 计算预算总额、总成本（优先用最终确认的预算类别）
        BigDecimal budgetTotal = BigDecimal.ZERO;
        BigDecimal costTotal = BigDecimal.ZERO;
        for (PmMaterialItem item : items) {
            budgetTotal = budgetTotal.add(item.getUserTotalPrice());
            costTotal = costTotal.add(item.getCostTotalPrice());
        }

        // 计算毛利率
        BigDecimal grossMargin = null;
        if (budgetTotal.compareTo(BigDecimal.ZERO) > 0) {
            grossMargin = budgetTotal.subtract(costTotal)
                    .divide(budgetTotal, 2, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"))
                    .setScale(1, RoundingMode.HALF_UP);
        }

        // 更新清单汇总
        PmMaterialList list = new PmMaterialList();
        list.setId(listId);
        list.setBudgetTotal(budgetTotal);
        list.setCostTotal(costTotal);
        list.setGrossMargin(grossMargin);
        list.setUpdateTime(LocalDateTime.now());
        updateById(list);
    }

    // 辅助方法：获取当前登录用户ID（若依框架）
    private Long getCurrentUserId() {
        return com.ruoyi.common.utils.SecurityUtils.getUserId();
    }

    // 辅助方法：获取当前登录用户名（若依框架）
    private String getCurrentUserName() {
        return com.ruoyi.common.utils.SecurityUtils.getUsername();
    }

}
